home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
c
/
ldb.zip
/
SBINDER.HPP
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-18
|
8KB
|
339 lines
/*
sbinder.hpp
10-18-91
Streamable Binder: Loose Data Binder v 1.4
Copyright 1991
John W. Small
All rights reserved
PSW / Power SoftWare
P.O. Box 10072
McLean, Virginia 22102 8072 USA
John Small
Voice: (703) 759-3838
CIS: 73757,2233
*/
#ifndef SBINDER_HPP
#define SBINDER_HPP
#include <iostream.h>
#include <iomanip.h>
#ifndef BINDER_HPP
#include "binder.hpp"
#endif
#define ID_Streamable 0
#define ID_StreamableRef ID_Streamable
#define ID_SBinder 1
class Streamable;
typedef Streamable * StreamablE;
#define StreamablE0 ((StreamablE)0)
class StreamableClassRegistry;
#define SCRegistry SCReg
extern StreamableClassRegistry SCRegistry;
/*
A class must include the STREAMABLE macro or its
equivalent in its public section and be derived
either publicly or privately from Streamable but
never virtually or otherwise multiply inherited
in order for it to be "streamable". Furthermore
it must have been linked to. The SBinder
primitives automatically link to and unlink from
Streamable nodes. That means the SBinder must
itself be linked before it can be streamed. See
SBinder below for an example without using the
STREAMABLE macro and SData for an example using
STREAMABLE.
*/
class Streamable {
friend StreamableClassRegistry;
voiD parenT;
unsigned id;
unsigned refCount, streamCount;
long streamPos;
/*
Stream contents:
1st & Only 1st of Many MultiRef
id x x 0
refCount 1 > 1
streamCount
streamPos x
user's data x x
*/
protected:
// Static so that the static load() can call!
static void lserror(const char *msg, unsigned id);
virtual void serror(const char *msg);
virtual void swarn(const char *msg);
virtual ostream& store(ostream& os)
{ return os; }
static StreamablE load(istream& is,
StreamablE InstancE);
void setID(unsigned id)
{ this->id = id; }
public:
static int refDebug;
static int streamDebug;
static char memberTermChar;
enum { ID_CLASS = 0 };
// The first parameter below, "dummy", insures that
// the STREAMABLE macro defines a unique constructor
// for derived classes!
Streamable(StreamableClassRegistry& dummy,
unsigned id = Streamable::ID_CLASS);
static void registerClass(unsigned id = ID_CLASS,
StreamablE (*loader)(istream& is,
StreamablE InstancE) = load);
operator StreamablE() { return this; }
voiD ParenT() { return parenT; }
unsigned ID() { return id; }
virtual unsigned restream();
unsigned unlink(voiD P = voiD0);
StreamablE link(voiD P = voiD0);
unsigned RefCount() { return refCount; }
virtual ~Streamable() {}
};
// stream manipulator: insert end of member field char
extern ostream& endm(ostream& os);
// stream manipulator: extract end of member field char
extern istream& nextm(istream& is);
/*
The STREAMABLE macro declares two functions: store()
and load() which you must define to store member
data onto a stream and to load that data back from
that stream. You must assign a unique id to each
streamable class and register every class that will
be stored on a stream. Don't forget to restream()
between operations!
*/
#define STREAMABLE(class, id, base) \
private: \
friend StreamableClassRegistry; \
protected: \
base :: lserror; \
base :: serror; \
base :: swarn; \
virtual ostream& store(ostream& os); \
static StreamablE load(istream& is, \
StreamablE InstancE); \
base :: setID; \
public: \
enum { ID_CLASS = id }; \
class (StreamableClassRegistry& dummy, \
unsigned cid = class ::ID_CLASS) \
: base (dummy,cid) {} \
operator StreamablE() \
{ return (StreamablE)this; } \
static void registerClass(unsigned cid = \
class ::ID_CLASS, \
StreamablE (*loader)(istream& is, \
StreamablE InstancE) = class ::load) \
{ base :: registerClass(cid,loader); } \
base :: ParenT; \
base :: ID; \
base :: restream; \
base :: unlink; \
base :: link; \
base :: RefCount
// value for dummy parameter of constructor above
#define UNIQUE_STREAMABLE SCRegistry
class SBinder : public Binder, public Streamable {
protected:
virtual int Dfree(voiD D);
virtual int Dattach(voiD D);
virtual void Ddetach(voiD D);
virtual ostream& store(ostream& os);
static StreamablE load(istream& is,
StreamablE InstancE);
virtual void Dstore(ostream& os, const voiD D);
virtual voiD Dload(istream& is);
public:
enum { ID_CLASS = ID_SBinder };
SBinder(StreamableClassRegistry& dummy,
unsigned id = ID_CLASS)
: Binder(OnlyInitBinderVFT),
Streamable(dummy,id) {}
SBinder(unsigned flags = BDR_OK_FREE,
unsigned maxNodes = BDR_MAXNODES,
unsigned limit = BDR_LIMIT,
unsigned delta = BDR_DELTA)
: Binder(flags,maxNodes,limit,delta),
Streamable(UNIQUE_STREAMABLE,ID_CLASS)
{}
SBinder(voiDV argv, int argc = 0,
unsigned flags = BDR_OK_FREE)
: Binder(argv,argc,flags),
Streamable(UNIQUE_STREAMABLE,ID_CLASS)
{}
static void registerClass(unsigned id = ID_CLASS,
StreamablE (*loader)(istream& is,
StreamablE InstancE) = load)
{ Streamable :: registerClass(id,loader); }
virtual unsigned restream();
virtual ~SBinder();
};
typedef SBinder * SBindeR;
#define SBindeR0 ((SBindeR)0)
/*
The StreamableClassRegistry holds the records of
classes and their static load functions. Load
functions have to be static because constructors
don't have addresses in C++. Store functions are
virtual and thus can be called automatically.
*/
struct StreamableClassRecord {
unsigned id;
StreamablE (*load)(istream& is,
StreamablE InstancE);
StreamableClassRecord(unsigned id,
StreamablE (*load)(istream& is,
StreamablE InstancE))
{ this->id = id; this->load = load; }
};
typedef StreamableClassRecord * SCRecorD;
#define SCRecorD0 ((SCRecorD)0)
struct InstanceHoldingRecord {
StreamablE InstancE;
unsigned refCount, streamCount;
long streamPos;
InstanceHoldingRecord(StreamablE InstancE,
unsigned refCount, long streamPos)
{
this->InstancE = InstancE;
this->refCount = refCount;
streamCount = 1;
this->streamPos = streamPos;
}
};
typedef InstanceHoldingRecord * IHRecorD;
#define IHRecorD0 ((IHRecorD)0)
class StreamableClassRegistry {
Binder ClassRecords;
Binder InstanceLinks;
protected:
virtual void error(char *msg, unsigned id = 0,
StreamablE InstancE = StreamablE0);
virtual void warn(char *msg, unsigned id = 0,
StreamablE InstancE = StreamablE0);
public:
static int debug;
StreamableClassRegistry()
: ClassRecords(BDR_OK_FREE),
InstanceLinks(BDR_OK_FREE)
{}
unsigned restream();
void registerClass(unsigned id, StreamablE (*loader)
(istream& is, StreamablE InstancE));
void forgetClasses();
istream& get(istream& is, StreamablE& InstancE);
ostream& put(ostream& os, StreamablE InstancE);
~StreamableClassRegistry() { forgetClasses(); }
};
#define RestreamRegistry() SCRegistry.restream()
inline istream& operator>>(istream& is, StreamablE& InstancE)
{
return SCRegistry.get(is,InstancE);
}
inline ostream& operator<<(ostream& os, StreamablE InstancE)
{
return SCRegistry.put(os, InstancE);
}
/*
FncPtrRegistry is provided so that you can stream
function pointers.
*/
typedef void (*GenericFnC)();
#define GenericFnC0 ((GenericFnC)0)
#define ID_UnknownGenericFnC 0
struct StreamableFncPtrRecord {
unsigned id;
GenericFnC fnC;
StreamableFncPtrRecord(unsigned id,
GenericFnC fnC)
{ this->id = id; this->fnC = fnC; }
};
typedef StreamableFncPtrRecord * SFPRecorD;
#define SFPRecorD0 ((SFPRecorD)0)
class StreamableFncPtrRegistry {
Binder FncPtrRecords;
public:
static int debug;
protected:
virtual void error(char *msg, unsigned id);
virtual void warn(char *msg, unsigned id);
public:
StreamableFncPtrRegistry() : FncPtrRecords() {}
void registerFunction(unsigned id,
GenericFnC fnC);
GenericFnC FnC(unsigned id);
unsigned ID(GenericFnC fnC);
~StreamableFncPtrRegistry()
{ FncPtrRecords.allFree(); }
};